#include "Buffer.h"

Buffer::Buffer(size_t initSize)
    : buffer_(initSize),
      readStart_(0),
      writeStart_(0)
{
}

Buffer::~Buffer()
{
}

bool Buffer::append(const std::string &data)
{
    return append(data.c_str(), data.size());
}

bool Buffer::append(const char *data, size_t len)
{
    if (!enableWrite(len))
    {
        printf("Buffer::append enableWrite failed!");
        assert(false);
        return false;
    }
    std::copy(data, data + len, buffer_.begin() + writeStart_);
    writeStart_ += len;
    return true;
}

std::string Buffer::retrieve(size_t len)
{
    len = std::min(len, readableSize());
    std::string data(buffer_.begin() + readStart_, buffer_.begin() + readStart_ + len);
    readStart_ += len;
    return data;
}

std::string Buffer::retrieveAll()
{
    std::string data(buffer_.begin() + readStart_, buffer_.begin() + writeStart_);
    readStart_ = 0;
    writeStart_ = 0;
    return data;
}

size_t Buffer::availableSize()
{
    return buffer_.size() - readableSize();
}

size_t Buffer::readableSize()
{
    return writeStart_ - readStart_;
}

unsigned char* Buffer::data()
{
    return buffer_.data() + readStart_;
}

bool Buffer::enableWrite(size_t size)
{
    if (availableSize() < size)
    {
        std::vector<unsigned char> _data(size + buffer_.size() * 2);
        assert(_data.size() == buffer_.size() * 2 + size);
        std::copy(buffer_.begin(), buffer_.end(), _data.begin());
        buffer_.swap(_data);
        writeStart_ = readableSize();
        readStart_ = 0;
    }
    else if (buffer_.size() - writeStart_ < size)
    {
        std::copy(buffer_.begin() + readStart_, buffer_.begin() + writeStart_, buffer_.begin());
        writeStart_ = readableSize();
        readStart_ = 0;
    }
    return true;
}
